package com.ulook.lookplanet.service;

import com.ulook.lookplanet.bean.TTopic;
import com.ulook.lookplanet.bean.VArticlePreInfo;
import com.ulook.lookplanet.mapper.SquareMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.stream.Collectors;

/**
 * 描述：
 *
 * @author L1998
 * @date 2021/4/15
 */
@Service
public class SquareService {

    @Autowired
    private SquareMapper mapper;

    /**
     * 获取热点话题
     */
    public List<TTopic> getHotTopic(){
        return mapper.getHotTopic();
    }

    /**
     * 获取推荐动态
     */
    public List<VArticlePreInfo> getSquareArticle(int currUserID, int itemNum){
        List<String> artIdList = recommendArticle(currUserID, itemNum);
        if(artIdList.size() != 0){
            return mapper.getArticleByIdList(artIdList, currUserID);
        }
        return new ArrayList<>();
    }

    /**
     * 推荐算法
     */
    private List<String> recommendArticle(int uid, int offset){
        List<Integer> userList;
        userList = mapper.getAllUserIdList();
        int N = userList.size();
//        System.out.println("用户数量："+N);
        int[][] sparseMatrix=new int[N][N]; //建立用户稀疏矩阵，用于用户相似度计算【相似度矩阵】
        for(int i=0;i<N;i++){
            for(int j=0;j<N;j++)
                sparseMatrix[i][j] = 0;
        }
        Map<Integer, Integer> userItemLength = new HashMap<>();//存储每一个用户对应的不同物品总数  eg: A 3
        Map<String, Set<Integer>> itemUserCollection = new HashMap<>();//建立物品到用户的倒排表 eg: a A B
        Set<String> items = new HashSet<>();//辅助存储物品集合
        Map<Integer, Integer> userID = new HashMap<>();//辅助存储每一个用户的用户ID映射:user->id
        Map<Integer, Integer> idUser = new HashMap<>();//辅助存储每一个ID对应的用户映射:id->user

        for(int i=0; i<N; i++){ //依次处理N个用户
            int user = userList.get(i);
            List<String> itemList = mapper.getLikeArticleByUserId(user);
            itemList.addAll(mapper.getCollectArticleByUserId(user));
            itemList.addAll(mapper.getHistoryArticleByUserId(user));
//            System.out.println("UserID:"+user+" 点赞收藏："+itemlist);
            userItemLength.put(user,itemList.size());
            //用户ID与稀疏矩阵建立对应关系
            userID.put(user,i);
            idUser.put(i,user);

            //1建立物品--用户倒排表
            for(int j=0; j < itemList.size(); j++){
                String topic = itemList.get(j);
                if(items.contains(topic)){ //如果已经包含对应的物品--用户映射，直接添加对应的用户
                    itemUserCollection.get(topic).add(user);
                }else{//否则创建对应物品--用户集合映射
                    items.add(topic);
                    //创建物品--用户倒排关系
                    itemUserCollection.put(topic, new HashSet<Integer>());
                    itemUserCollection.get(topic).add(user);
                }
            }
        }
        //输出倒排关系表
        System.out.println("输出倒排关系表：\n"+itemUserCollection.toString());

        //2计算相似度矩阵【稀疏】
        Set<Map.Entry<String, Set<Integer>>> entrySet = itemUserCollection.entrySet();
        Iterator<Map.Entry<String, Set<Integer>>> iterator = entrySet.iterator();
        while (iterator.hasNext()){
            Set<Integer> commonUsers=iterator.next().getValue();
            for(int user_u : commonUsers){
                for(int user_v : commonUsers){
                    if(user_u == user_v){
                        continue;
                    }
                    //计算用户u与用户v都有正反馈的物品总数
                    sparseMatrix[userID.get(user_u)][userID.get(user_v)]+=1;
                }
            }
        }
        //计算用户之间的相似度【余弦相似性】
        Integer recommendUserId = userID.get(uid);
        for(int j=0;j<sparseMatrix.length;j++){
            if(j!=recommendUserId){
                System.out.println(idUser.get(recommendUserId)+"--"+idUser.get(j)+"相似度:"
                        +sparseMatrix[recommendUserId][j]/Math.sqrt(userItemLength.get(idUser.get(recommendUserId))*userItemLength.get(idUser.get(j))));
            }
        }

        //4计算指定用户recommendUser的物品推荐度
        Map<String, Double> itemRecommendDegree = new HashMap<>(); //topic->推荐度
        ArrayList<String> hasRead = new ArrayList<>();  // 阅读过的
        for(String item : items){//遍历每一件物品
            //得到购买当前物品的所有用户集合
            Set<Integer> users = itemUserCollection.get(item);
            //如果被推荐用户没有购买当前物品，则进行推荐度计算
            if(!users.contains(uid)){
                double RecommendDegree = 0.0;
                for(int user : users){
                    //推荐度计算
                    RecommendDegree += sparseMatrix[userID.get(uid)][userID.get(user)] / Math.sqrt(userItemLength.get(uid) * userItemLength.get(user));
                }
                itemRecommendDegree.put(item, RecommendDegree);
            }else {
                hasRead.add(item);
            }
        }
        System.out.println("TopicID,推荐度\n"+itemRecommendDegree);

        //取指定位置的8个
        if(itemRecommendDegree.size() <= (offset)){
            List<String> list1 = mapper.getArticleIdList(offset - itemRecommendDegree.size());
            List<String> list2 = new ArrayList<>();
            if(list1 != null){
                for(String key : list1){
                    if(list2.size() == 8)
                        break;
                    if(itemRecommendDegree.containsKey(key)){
                        continue;
                    }
                    list2.add(key);
                }
                System.out.println("list1--");
                System.out.println(list1);
                return list1.subList(0, Math.min(8, list1.size()));
            }else {
                return new ArrayList<>();
            }
        }else {
            int end = Math.min(itemRecommendDegree.size(), offset + 8);
            List<String> list = itemRecommendDegree.entrySet().stream()
                    .sorted((entry1, entry2) -> entry2.getValue().compareTo(entry1.getValue()))
                    .map(entry -> entry.getKey()).collect(Collectors.toList())
                    .subList(offset, end);
            System.out.println(list);
            return list;
        }

    }
}
